//@author A0096759E

package logic;

import java.util.Stack;

import storage.ScheduleEvent;
import storage.Storage;
import storage.UndoRedoStackEntry;
import applogger.AppLogger;

public class ScheduleUndoer {
	
	private static final String ADD_COMMAND = "add";
	private static final String DELETE_COMMAND = "del";
	private static final String CLEAR_COMMAND = "clr";
	private static final String MARK_DONE_COMMAND = "done";
	private static final String MARK_UNDONE_COMMAND = "undone";
	private static final String MODIFY_COMMAND = "mod";
	
	private static final String ERROR_MSG_CANNOT_UNDO = "Unable to Undo! No last command found!";
	private static final String SUCCESS_MSG_UNDO_CLEAR = "Successfully restored the Schedule!";
	private static final String SUCCESS_MSG_UNDO_MOD = "Successfully un-modified Event!";
	
	private Storage eventsList;
	private Stack<UndoRedoStackEntry> undoStack;
	
	/**
	 * Constructor for ScheduleUndoer. Takes in the current LifeShelf storage.
	 * @param eventsList
	 */
	public ScheduleUndoer(Storage eventsList) {
		this.eventsList = eventsList;
		this.undoStack = eventsList.getUndoStack();
	}
	
	/**
	 * Looks at the undo stack. Decodes it and calls the respective methods to undo the action
	 * @return
	 */
	public String undoLast() {
		if (undoStack.empty()) return ERROR_MSG_CANNOT_UNDO; 
		String lastDoneCommand = undoStack.peek().getCommand();
		switch (lastDoneCommand) {
		case ADD_COMMAND:
			return undoLastAdd();
		case DELETE_COMMAND:
			return undoLastDelete();
		case CLEAR_COMMAND:
			return undoLastClear();
		case MARK_DONE_COMMAND:
			return undoLastMarkDone();
		case MARK_UNDONE_COMMAND:
			return undoLastMarkUndone();
		case MODIFY_COMMAND:
			return undoLastModify();
		}
		return ERROR_MSG_CANNOT_UNDO;
	}

	/**
	 * Undoes the last add command
	 * @return a success message if done, or error message if not
	 */
	private String undoLastAdd() {
		AppLogger.log("Undoing Last Add");
		ScheduleEvent lastAdded = undoStack.pop().getEvent();
		eventsList.getRedoStack().push(new UndoRedoStackEntry(DELETE_COMMAND, lastAdded));
		return eventsList.deleteEvent(eventsList.getEventIndex(lastAdded)+1);
	}

	/**
	 * Undoes the last delete command
	 * @return a success message if done, or error message if not
	 */
	private String undoLastDelete() {
		AppLogger.log("Undoing Last Delete");
		ScheduleEvent lastDeleted = undoStack.pop().getEvent();
		eventsList.getRedoStack().push(new UndoRedoStackEntry(ADD_COMMAND, lastDeleted));
		return eventsList.addEvent(lastDeleted);
	}	

	/**
	 * Undoes the last clear command
	 * @return a success message if done, or error message if not
	 */
	private String undoLastClear() {
		AppLogger.log("Undoing Last Clear");
		while (!undoStack.empty() && undoStack.peek().getCommand().equals(CLEAR_COMMAND)) {
			ScheduleEvent lastCleared = undoStack.pop().getEvent();
			eventsList.addEvent(lastCleared);
		}
		eventsList.getRedoStack().push(new UndoRedoStackEntry(CLEAR_COMMAND, null));
		return SUCCESS_MSG_UNDO_CLEAR;
	}

	/**
	 * Undoes the last modify command
	 * @return a success message if done, or error message if not
	 */
	private String undoLastModify() {
		AppLogger.log("Undoing Last Modify");
		undoStack.pop(); //to remove mod entry
		undoLastAdd();
		undoStack.peek().getEvent().setGoogleUID(null);
		undoLastDelete();
		eventsList.getRedoStack().push(new UndoRedoStackEntry(MODIFY_COMMAND, null));
		return SUCCESS_MSG_UNDO_MOD;
	}

	/**
	 * Undoes the last mark command
	 * @return a success message if done, or error message if not
	 */
	private String undoLastMarkDone() {
		AppLogger.log("Undoing Last Mark Done");
		ScheduleEvent lastMarked = undoStack.pop().getEvent();
		eventsList.getRedoStack().push(new UndoRedoStackEntry(MARK_UNDONE_COMMAND, lastMarked));
		return eventsList.markEventUndone(eventsList.getEventIndex(lastMarked)+1);
	}
	
	/**
	 * Undoes the last unmark command
	 * @return a success message if done, or error message if not
	 */
	private String undoLastMarkUndone() {
		AppLogger.log("Undoing Last Mark Not Done");
		ScheduleEvent lastUnmarked = undoStack.pop().getEvent();
		eventsList.getRedoStack().push(new UndoRedoStackEntry(MARK_DONE_COMMAND, lastUnmarked));
		return eventsList.markEventDone(eventsList.getEventIndex(lastUnmarked)+1);
	}
}
